import pandas as pd
import numpy as np
from sklearn.feature_selection import chi2, SelectKBest
from sklearn.preprocessing import LabelEncoder
import matplotlib.pyplot as plt
import seaborn as sns

# 设置随机种子，确保结果可复现
np.random.seed(42)


# 创建一个示例数据集
def create_sample_data(n_samples=1000):
    # 生成特征
    gender = np.random.choice(['男', '女'], size=n_samples)
    education = np.random.choice(['高中', '本科', '硕士', '博士'], size=n_samples)
    income_level = np.random.choice(['低', '中', '高'], size=n_samples)
    occupation = np.random.choice(['学生', '上班族', '自由职业', '退休'], size=n_samples)

    # 模拟特征与标签之间的关联（确保某些特征与标签有更强的关联）
    # 假设性别和教育水平与购买意愿有较强关联
    purchase_prob = np.zeros(n_samples)

    # 女性购买概率更高
    purchase_prob[gender == '女'] += 0.3

    # 教育水平越高，购买概率越高
    edu_impact = {'高中': 0, '本科': 0.1, '硕士': 0.2, '博士': 0.3}
    for edu, impact in edu_impact.items():
        purchase_prob[education == edu] += impact

    # 高收入者购买概率更高
    income_impact = {'低': 0, '中': 0.1, '高': 0.2}
    for income, impact in income_impact.items():
        purchase_prob[income_level == income] += impact

    # 加入随机噪声
    purchase_prob += np.random.normal(0, 0.1, n_samples)

    # 确保概率在0-1之间
    purchase_prob = np.clip(purchase_prob, 0, 1)

    # 生成购买意愿标签（二分类）
    purchase_intention = np.random.binomial(1, purchase_prob)

    # 创建DataFrame
    data = pd.DataFrame({
        '性别': gender,
        '教育水平': education,
        '收入水平': income_level,
        '职业': occupation,
        '购买意愿': purchase_intention
    })

    return data


# 生成示例数据
data = create_sample_data()
print("示例数据集前5行:")
print(data.head())

# 数据预处理：将分类特征转换为数值
# 注意：卡方检验需要数值型数据，因此我们需要将分类特征编码为整数
label_encoders = {}
categorical_features = ['性别', '教育水平', '收入水平', '职业']
X_encoded = pd.DataFrame()

for feature in categorical_features:
    le = LabelEncoder()
    X_encoded[feature] = le.fit_transform(data[feature])
    label_encoders[feature] = le

# 提取标签
y = data['购买意愿']

# 执行卡方检验
# 使用SelectKBest和chi2计算每个特征与标签之间的卡方值和p值
selector = SelectKBest(chi2, k='all')
selector.fit(X_encoded, y)

# 获取卡方值和p值
chi2_scores = selector.scores_
p_values = selector.pvalues_

# 创建结果DataFrame
results = pd.DataFrame({
    '特征': categorical_features,
    '卡方值': chi2_scores,
    'p值': p_values,
    '相关性强度': ['强' if p < 0.001 else '中' if p < 0.05 else '弱' if p < 0.1 else '无' for p in p_values]
})

# 按卡方值降序排序
results = results.sort_values('卡方值', ascending=False)
print("\n卡方检验结果:")
print(results)

# 可视化卡方值
plt.figure(figsize=(10, 6))
sns.barplot(x='卡方值', y='特征', data=results)
plt.title('特征与购买意愿之间的卡方值')
plt.tight_layout()
plt.savefig('chi2_scores.png')
plt.show()

# 可视化p值
plt.figure(figsize=(10, 6))
sns.barplot(x='p值', y='特征', data=results)
plt.axvline(x=0.05, color='r', linestyle='--', label='显著性水平(0.05)')
plt.title('特征与购买意愿之间的p值')
plt.legend()
plt.tight_layout()
plt.savefig('p_values.png')
plt.show()

# 深入分析：以性别为例，创建列联表
gender_ct = pd.crosstab(data['性别'], data['购买意愿'])
print("\n性别与购买意愿的列联表:")
print(gender_ct)

# 计算性别与购买意愿的卡方值（手动实现，与sklearn结果一致）
from scipy.stats import chi2_contingency

chi2_stat, p, dof, expected = chi2_contingency(gender_ct)
print(f"\n手动计算的性别与购买意愿的卡方值: {chi2_stat:.4f}, p值: {p:.4f}")

# 选择最重要的特征
# 假设我们想选择p值小于0.05的特征
selected_features = results[results['p值'] < 0.05]['特征'].tolist()
print(f"\n根据卡方检验，最重要的特征是: {selected_features}")
